package io.gitee.mingbaobaba.security.plugin.oauth2.jpa.repository;

import io.gitee.mingbaobaba.security.core.utils.JsonUtil;
import io.gitee.mingbaobaba.security.oauth2.domain.SecurityOauth2Client;
import io.gitee.mingbaobaba.security.oauth2.domain.SecurityOauth2Details;
import io.gitee.mingbaobaba.security.oauth2.repository.SecurityOauth2Repository;
import io.gitee.mingbaobaba.security.plugin.oauth2.jpa.entity.SecurityOauth2AccessTokenEntity;
import io.gitee.mingbaobaba.security.plugin.oauth2.jpa.entity.SecurityOauth2AuthorizationEntity;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Objects;
import java.util.Optional;


/**
 * <p>jpa oauth2存储实现</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/9/14 4:35
 */
public class SecurityOauth2JpaRepository implements SecurityOauth2Repository {

    @Autowired
    private SecurityOauth2JpaAuthorizationRepository securityOauth2AuthorizationRepository;

    @Autowired
    private SecurityOauth2JpaAccessTokenRepository securityOauth2AccessTokenRepository;

    @Override
    public void saveAuthorizationCode(String authorizationCode, SecurityOauth2Client securityClientMode, long timeout) {
        SecurityOauth2AuthorizationEntity securityOauth2Authorization = new SecurityOauth2AuthorizationEntity();
        securityOauth2Authorization.setAuthorizationCode(authorizationCode);
        securityOauth2Authorization.setAuthorizationData(JsonUtil.objectToJsonStr(securityClientMode));
        securityOauth2Authorization.setTimeout(timeout);
        securityOauth2Authorization.setCreateTime(LocalDateTime.now());
        securityOauth2Authorization.setUpdateTime(LocalDateTime.now());
        securityOauth2AuthorizationRepository.save(securityOauth2Authorization);
    }

    @Override
    public SecurityOauth2Client getClientModelByAuthorizationCode(String authorizationCode) {
        Optional<SecurityOauth2AuthorizationEntity> optional = securityOauth2AuthorizationRepository.findById(authorizationCode);
        if (!optional.isPresent()) {
            return null;
        }
        SecurityOauth2AuthorizationEntity securityOauth2Authorization = optional.get();
        //判断是否超时
        if (securityOauth2Authorization.getCreateTime().plusSeconds(securityOauth2Authorization.getTimeout()).isBefore(LocalDateTime.now())) {
            //已超时,删除信息
            removeAuthorizationCode(authorizationCode);
            return null;
        }
        return JsonUtil.jsonStrToObject(securityOauth2Authorization.getAuthorizationData(), SecurityOauth2Client.class);
    }

    @Override
    public void removeAuthorizationCode(String authorizationCode) {
        securityOauth2AuthorizationRepository.deleteById(authorizationCode);
    }

    @Override
    public boolean saveOauth2TokenDetails(SecurityOauth2Details securityOauth2Details, Long timeout) {
        SecurityOauth2AccessTokenEntity securityOauth2AccessTokenEntity = new SecurityOauth2AccessTokenEntity();
        securityOauth2AccessTokenEntity.setRefreshToken(securityOauth2Details.getRefreshToken());
        securityOauth2AccessTokenEntity.setAccessToken(securityOauth2Details.getAccessToken());
        securityOauth2AccessTokenEntity.setLoginId(securityOauth2Details.getLoginId());
        securityOauth2AccessTokenEntity.setUsername(securityOauth2Details.getUsername());
        securityOauth2AccessTokenEntity.setClientId(securityOauth2Details.getClientId());
        securityOauth2AccessTokenEntity.setTimeout(timeout);
        securityOauth2AccessTokenEntity.setCreateTime(LocalDateTime.now());
        securityOauth2AccessTokenEntity.setUpdateTime(LocalDateTime.now());
        securityOauth2AccessTokenRepository.save(securityOauth2AccessTokenEntity);
        return true;
    }

    @Override
    public SecurityOauth2Details getOauth2DetailsByAccessToken(String accessToken) {
        SecurityOauth2AccessTokenEntity securityOauth2AccessTokenEntity = securityOauth2AccessTokenRepository.findByAccessToken(accessToken);
        SecurityOauth2Details securityOauth2Details = null;
        if (Objects.nonNull(securityOauth2AccessTokenEntity)) {
            securityOauth2Details = new SecurityOauth2Details();
            securityOauth2Details.setAccessToken(securityOauth2AccessTokenEntity.getAccessToken());
            securityOauth2Details.setRefreshToken(securityOauth2AccessTokenEntity.getRefreshToken());
            securityOauth2Details.setUsername(securityOauth2AccessTokenEntity.getUsername());
            securityOauth2Details.setClientId(securityOauth2AccessTokenEntity.getClientId());
            securityOauth2Details.setExpiresIn(securityOauth2AccessTokenEntity.getTimeout());
        }
        return securityOauth2Details;
    }

    @Override
    public String accessTokenByRefreshToken(String refreshToken) {
        Optional<SecurityOauth2AccessTokenEntity> optional = securityOauth2AccessTokenRepository.findById(refreshToken);
        if (!optional.isPresent()) {
            return null;
        }
        SecurityOauth2AccessTokenEntity securityOauth2AccessTokenEntity = optional.get();
        //判断是否超时
        if (securityOauth2AccessTokenEntity.getCreateTime().plusSeconds(securityOauth2AccessTokenEntity.getTimeout()).isBefore(LocalDateTime.now())) {
            //已超时,删除信息
            securityOauth2AccessTokenRepository.deleteById(refreshToken);
            return null;
        }
        return securityOauth2AccessTokenEntity.getAccessToken();
    }

    @Override
    public Long refreshTokenTimeOut(String refreshToken) {
        Optional<SecurityOauth2AccessTokenEntity> optional = securityOauth2AccessTokenRepository.findById(refreshToken);
        if (!optional.isPresent()) {
            return 0L;
        }
        SecurityOauth2AccessTokenEntity securityOauth2AccessTokenEntity = optional.get();
        long timeout = securityOauth2AccessTokenEntity.getCreateTime()
                .plusSeconds(securityOauth2AccessTokenEntity.getTimeout()).toEpochSecond(ZoneOffset.ofHours(8)) -
                LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8));
        return timeout > 0 ? timeout : 0L;
    }
}
